home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Celestin Apprentice 5
/
Apprentice-Release5.iso
/
Source Code
/
C
/
Applications
/
Fixation 1.3
/
tcpstuff.c
< prev
next >
Wrap
Text File
|
1996-04-02
|
25KB
|
915 lines
// tcpstuff.cpp
// most copyright John Norstad
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <stdio.h>
#include "mytypes.h"
#include "MyMacTCP.h"
#include "error.h"
#include "util.h"
#include "tcpstuff.h"
#include "globals.h"
#include "preffile.h"
/* Types. */
typedef struct TStream { /* Stream info */
TCPiopb pBlock; /* MacTCP parameter block (must be first, unused with
Open Transport) */
unsigned long serverAddr; /* IP address of server */
unsigned short serverPort; /* port number on server */
unsigned short localPort; /* local port number */
// CStr255 command; /* last command sent on stream */
// CStr255 response; /* last response received on stream */
long responseCode; /* last response code received on stream */
Boolean closing; /* true when closing stream */
Boolean otherSideHasClosed; /* true when other side has closed its end of
the stream */
Boolean weHaveClosed; /* true when we have closed our end of the stream */
Boolean release; /* true when stream should be released */
long bytesIn; /* number of bytes received on stream */
long bytesOut; /* number of bytes sent on stream */
short myID;
/* Fields used only with MacTCP. */
long myA5; /* our A5 register */
StreamPtr tcpStream; /* MacTCP stream pointer */
struct wdsEntry wds[2]; /* MacTCP write data structure */
char mactcpBuf[1]; /* MacTCP buffer - size depends on MTU (must be last) */
} TStream, *TStreamPtr;
// defines for sending data
enum {
kNumSmallOut = 8,
kNumMidOut = 2,
kNumLargeOut = 2,
kNumOutChunks = kNumSmallOut + kNumMidOut + kNumLargeOut,
kSmallOutSize = 24,
kMidOutSize = 128,
kLargeOutSize = 2048
};
typedef struct {
TCPiopb pBlock;
struct wdsEntry wds[2]; /* MacTCP write data structure */
short bufSize;
uchar buf[2]; // variable size
} OutChunk;
OutChunk *outChunk[kNumOutChunks];
static short gRefNum; /* MacTCP driver reference number */
static long gStreamBufSize; /* stream buffer size */
static long gTCPBufSize; /* TCP buffer size for MacTCP */
static UniversalProcPtr gOldExitToShellUPP;
static UniversalProcPtr gMyExitToShellUPP;
static ResultUPP gMacTCPDNRResultProcUPP = nil;
static TCPIOCompletionUPP gMacTCPCloseStreamCompletionRoutineUPP = nil;
static Boolean gMacTCPDNROperationInProgress = false;
unsigned long gMyAddress;
unsigned char buf[kMaxStreams][kBufferLength];
long bufdata[kMaxStreams];
TStream *myStream[kMaxStreams];
short nexStatus[kMaxStreams];
/*----------------------------------------------------------------------------
NewStreamBuffer
Allocate a stream buffer.
Exit: function result = error code.
*s = pointer to new stream buffer.
----------------------------------------------------------------------------*/
static TStreamPtr NewStreamBuffer (void)
{
OSErr err = noErr;
TStreamPtr s;
s = (TStreamPtr) NewPtr(gStreamBufSize);
if (!s) return nil;
memset(s, 0, sizeof(TStream));
s->myA5 = SetCurrentA5();
return s;
}
/*----------------------------------------------------------------------------
InitMacTCPParamBlock
Initialize a MacTCP parameter block.
Entry: pBlock = pointer to parameter block.
csCode = MacTCP control code (TCPCreate, etc.).
----------------------------------------------------------------------------*/
static void InitMacTCPParamBlock (TCPiopb *pBlock, short csCode)
{
memset(pBlock, 0, sizeof(TCPiopb));
pBlock->ioResult = 1;
pBlock->ioCRefNum = gRefNum;
pBlock->csCode = csCode;
}
/*----------------------------------------------------------------------------
CallMacTCP
Call MacTCP and wait for the call to complete.
Entry: s = pointer to stream.
returnImmediatelyOnError = true to return immediately if
the GiveTime function returns an error.
Exit: function result = error code.
----------------------------------------------------------------------------*/
static OSErr CallMacTCP (TStreamPtr s, Boolean returnImmediatelyOnError)
{
OSErr err = noErr, giveTimeErr = noErr;
PBControlAsync((ParmBlkPtr)&s->pBlock);
do {
// giveTimeErr = (*gGiveTime)();
// if (err == noErr) err = giveTimeErr;
// if (err != noErr && returnImmediatelyOnError) return err;
} while (s->pBlock.ioResult > 0);
err = s->pBlock.ioResult;
// if (err == connectionClosing || err == connectionDoesntExist ||
// err == connectionTerminated) s->otherSideHasClosed = true;
return err;
}
static inline void CallMacTCPAsynch(TCPiopb *pBlock)
{
PBControlAsync((ParmBlkPtr)pBlock);
}
/*----------------------------------------------------------------------------
MacTCPDNRResultProc
MacTCP domain name resolver completion routine.
Entry: hInfoPtr = pointer to hostInfo struct.
userDataPtr = pointer to user data.
----------------------------------------------------------------------------*/
static pascal void MacTCPDNRResultProc (struct hostInfo *hInfoPtr, char *userDataPtr)
{
*(Boolean*)userDataPtr = true;
}
/*----------------------------------------------------------------------------
MacTCPCloseStreamCompletionRoutine
This is the asynchronous MacTCP completion routine used to close streams.
This completion routine chains to itself to do the following tasks
involved in gracefully tearing down a stream in the background:
Wait for QUIT command send to complete (the send is initiated by the
NetClose function below).
Read incoming data until an error occurs (signalling that the
server has closed its end of the connection).
Close our end of the connection.
Entry: pBlock = pointer to MacTCP parameter block.
----------------------------------------------------------------------------*/
static void MacTCPCloseStreamCompletionRoutine (TCPiopb *pBlock)
{
TStreamPtr s;
OSErr err = noErr;
long savedA5;
s = (TStreamPtr)pBlock;
savedA5 = SetA5(s->myA5);
if (s->pBlock.csCode == TCPSend) {
/* The QUIT command has been sent. Start the first receive. */
err = s->pBlock.ioResult;
if (err != noErr) {
s->release = true;
SetA5(savedA5);
return;
}
InitMacTCPParamBlock(&s->pBlock, TCPRcv);
s->pBlock.csParam.receive.rcvBuff = (Ptr) buf[s->myID];
s->pBlock.csParam.receive.rcvBuffLen = kBufferLength;
} else if (s->pBlock.csCode == TCPRcv) {
/* A receive operation has finished. If there was no error, start another
receive. If an error occurred, it was because the server has closed
its side of the connection. In this case, if we have already closed
our side of the connection, set the "release" flag to signal that
we can now release the stream and dispose of the queue element. If
we have not yet closed our side, we start the TCPClose. */
err = s->pBlock.ioResult;
if (err == noErr) {
InitMacTCPParamBlock(&s->pBlock, TCPRcv);
s->pBlock.csParam.receive.rcvBuff = (Ptr) buf[s->myID];
s->pBlock.csParam.receive.rcvBuffLen = kBufferLength;
} else {
s->otherSideHasClosed = true;
if (s->weHaveClosed) {
s->release = true;
SetA5(savedA5);
return;
} else {
InitMacTCPParamBlock(&s->pBlock, TCPClose);
}
}
} else if (s->pBlock.csCode == TCPClose) {
/* Our close has finished. If the other side has also closed,
set the "release" flag to signal that we can now release
the stream and dispose of the queue element. If the other
side has not yet closed, issue a receive operation and wait
for the other side to close. */
s->weHaveClosed = true;
if (s->otherSideHasClosed) {
s->release = true;
SetA5(savedA5);
return;
} else {
InitMacTCPParamBlock(&s->pBlock, TCPRcv);
s->pBlock.csParam.receive.rcvBuff = (Ptr) buf[s->myID];
s->pBlock.csParam.receive.rcvBuffLen = kBufferLength;
}
}
/* Issue the next PBControl call in the chain. */
s->pBlock.ioCompletion = gMacTCPCloseStreamCompletionRoutineUPP;
s->pBlock.tcpStream = s->tcpStream;
s->pBlock.ioResult = 1;
err = PBControlAsync((ParmBlkPtr)&s->pBlock);
if (err != noErr) s->release = true;
SetA5(savedA5);
}
/*----------------------------------------------------------------------------
NetGetMyAddr
Get this Mac's IP address.
Exit: function result = error code.
*addr = the IP address of this Mac.
With Open Transport, if the Mac has more than one IP interface, the
IP address of the default interface is returned.
----------------------------------------------------------------------------*/
static OSErr NetGetMyAddr (unsigned long *addr)
{
struct GetAddrParamBlock pBlock;
OSErr err = noErr, giveTimeErr = noErr;
static Boolean gotIt = false;
static unsigned long myAddr;
if (!gotIt) {
memset(&pBlock, 0, sizeof(pBlock));
pBlock.ioResult = 1;
pBlock.csCode = ipctlGetAddr;
pBlock.ioCRefNum = gRefNum;
PBControlAsync((ParmBlkPtr)&pBlock);
while (pBlock.ioResult > 0) {
// giveTimeErr = (*gGiveTime)();
if (err == noErr) err = giveTimeErr;
}
if (err != noErr) return err;
err = pBlock.ioResult;
if (err != noErr) return err;
myAddr = pBlock.ourAddress;
gotIt = true;
}
*addr = myAddr;
return noErr;
}
/*----------------------------------------------------------------------------
GetMaxTCPMTU
Get the max MTU size.
Exit: function result = max MTU, or 0 if error.
----------------------------------------------------------------------------*/
static long GetMaxTCPMTU (void)
{
UDPiopb iopb;
OSErr err = noErr;
memset(&iopb, 0, sizeof(iopb));
err = NetGetMyAddr(&iopb.csParam.mtu.remoteHost);
if (err != noErr) return 0;
iopb.ioCRefNum = gRefNum;
iopb.csCode = UDPMaxMTUSize;
err = PBControlSync((ParmBlkPtr)&iopb);
if (err != noErr) return 0;
return iopb.csParam.mtu.mtuSize;
}
/*----------------------------------------------------------------------------
DoTCPCreate
Create a stream.
Entry: s = pointer to stream.
Exit: function result = error code.
----------------------------------------------------------------------------*/
static OSErr DoTCPCreate (TStreamPtr s)
{
OSErr err = noErr;
InitMacTCPParamBlock(&s->pBlock, TCPCreate);
s->pBlock.csParam.create.rcvBuff = s->mactcpBuf;
s->pBlock.csParam.create.rcvBuffLen = gTCPBufSize;
err = CallMacTCP(s, false);
if (err != noErr) return err;
s->tcpStream = s->pBlock.tcpStream;
return noErr;
}
/*----------------------------------------------------------------------------
DoTCPRelease
Release a stream.
Entry: s = pointer to stream.
Exit: function result = error code.
Any active connection is also aborted, if necessary, before releasing
the stream.
With MacTCP, the function uses its own TCPiopb parameter block instead
of the one inside the stream block, because the one inside the stream block
may already be in use by some other asynchronous operation.
----------------------------------------------------------------------------*/
static OSErr DoTCPRelease (short stream)
{
TCPiopb pBlock;
OSErr err = noErr, giveTimeErr = noErr;
Boolean abort;
TStreamPtr s;
s = myStream[stream];
if (!s || !s->tcpStream) return noErr;
InitMacTCPParamBlock(&pBlock, TCPRelease);
pBlock.tcpStream = s->tcpStream;
PBControlAsync((ParmBlkPtr)&pBlock);
while (pBlock.ioResult > 0) {
// giveTimeErr = (*gGiveTime)();
// if (err == noErr) err = giveTimeErr;
}
if (err == noErr) err = pBlock.ioResult;
if (err == noErr) {
s->tcpStream = 0; // we know we're done with it
nexStatus[stream] = kStatClosed;
}
return err;
}
/*----------------------------------------------------------------------------
DoTCPActiveOpen
Open an active stream.
Entry: s = pointer to stream.
addr = IP address of server.
port = port number of service.
Exit: function result = error code.
----------------------------------------------------------------------------*/
OSErr DoTCPActiveOpen (short stream, unsigned long addr,
unsigned short port)
{
OSErr err = noErr;
TStreamPtr s = myStream[stream];
InitMacTCPParamBlock(&s->pBlock, TCPActiveOpen);
s->pBlock.tcpStream = s->tcpStream;
s->pBlock.csParam.open.remoteHost = addr;
s->pBlock.csParam.open.remotePort = port;
err = CallMacTCP(s, true);
if (err == noErr)
s->localPort = s->pBlock.csParam.open.localPort;
return err;
}
/*----------------------------------------------------------------------------
DoTCPPassiveOpen
Open a passive stream.
Entry: s = pointer to stream.
Exit: function result = error code.
*port = assigned unused local port number.
Note: Unlike the other "DoTCPxxx" functions, DoTCPPassiveOpen is
asynchronous. The passive stream is opened, but the function does not
wait for another host to connect. The function is used by
NetFTPDataPassiveOpen to open passive FTP data streams. The caller must
call NetFTPDataWaitForConnection to wait for the FTP server to connect
to the stream.
----------------------------------------------------------------------------*/
OSErr DoTCPPassiveOpen (short stream, unsigned short *port)
{
OSErr err = noErr;
TStreamPtr s = myStream[stream];
InitMacTCPParamBlock(&s->pBlock, TCPPassiveOpen);
s->pBlock.tcpStream = s->tcpStream;
s->pBlock.csParam.open.localPort = *port;
PBControlAsync((ParmBlkPtr)&s->pBlock);
while (s->pBlock.csParam.open.localPort == 0) {
// err = (*gGiveTime)();
// if (err != noErr) return err;
}
*port = s->localPort = s->pBlock.csParam.open.localPort;
return noErr;
}
/*----------------------------------------------------------------------------
DoTCPSend
Send data on a stream.
Entry: s = pointer to stream.
data = pointer to data to send.
len = length of data to send.
push = true to set push data flag. This flag should be set on
the last buffer of data being sent on the stream before
a response from the server is expected. This flag is need
to keep IBM VM/CMS happy. (Note OT handles this internally,
so this is needed only with MacTCP.)
Exit: function result = error code.
----------------------------------------------------------------------------*/
static OSErr OldDoTCPSend (TStreamPtr s, void *data, unsigned short len, Boolean push)
{
OSErr err = noErr;
// TCPiopb pBlock;
s->wds[0].ptr = (Ptr) data;
s->wds[0].length = len;
InitMacTCPParamBlock(&s->pBlock, TCPSend);
s->pBlock.tcpStream = s->tcpStream;
s->pBlock.csParam.send.wdsPtr = (Ptr)s->wds;
s->pBlock.csParam.send.pushFlag = push;
err = CallMacTCP(s, true);
return err;
}
static OSErr DoTCPSend (TStreamPtr s, void *data, unsigned short len, Boolean push)
{
OSErr err = noErr;
short nnn;
for (nnn=0;nnn<kNumOutChunks;nnn++) {
OutChunk *oc = outChunk[nnn];
verify(oc);
if (oc->bufSize < len)
continue;
if (oc->pBlock.ioResult > 0)
continue; // already being used
// okay, I think we're ready to use it and send
oc->wds[0].ptr = (Ptr) oc->buf;
oc->wds[0].length = len;
memcpy(oc->buf, data, len);
InitMacTCPParamBlock(&oc->pBlock, TCPSend);
oc->pBlock.tcpStream = s->tcpStream;
oc->pBlock.csParam.send.wdsPtr = (Ptr)oc->wds;
oc->pBlock.csParam.send.pushFlag = push;
CallMacTCPAsynch(&oc->pBlock);
return noErr;
}
tprintf("Error writing data: no available buffers!\r");
return -1;
}
OSErr
SendData(short stream, void *data, long length)
{
OSErr err;
if (length == 0)
return noErr;
if (nexStatus[stream] != kStatOpen)
return -1;
if (err = DoTCPSend(myStream[stream], data, length, true))
VDebugStr("Error writing data!");
return err;
}
/*----------------------------------------------------------------------------
DoTCPRcv
Reveive data on a stream.
Entry: s = pointer to stream.
data = pointer to data buffer.
*len = length of data buffer.
Exit: function result = error code.
*len = number of bytes received.
----------------------------------------------------------------------------*/
static OSErr DoTCPRcv (TStreamPtr s, Ptr data, unsigned short *len)
{
OSErr err = noErr;
InitMacTCPParamBlock(&s->pBlock, TCPRcv);
s->pBlock.tcpStream = s->tcpStream;
s->pBlock.csParam.receive.rcvBuff = StripAddress(data);
s->pBlock.csParam.receive.rcvBuffLen = *len;
err = CallMacTCP(s, true);
*len = s->pBlock.csParam.receive.rcvBuffLen;
if (err == noErr) s->bytesIn += *len;
return err;
}
void ReleaseStreams(void)
{
short nnn;
for (nnn=0;nnn<kMaxStreams;nnn++)
if (myStream[nnn] != nil && myStream[nnn]->tcpStream != nil)
DoTCPRelease(nnn);
}
OSErr
PrepareTheWay(short stream)
{
OSErr err;
if (err = DoTCPCreate(myStream[stream]))
VDebugStr("Error on create: stream %d", stream);
return err;
}
/*----------------------------------------------------------------------------
MyExitToShell
ExitToShell trap patch (for MacTCP only).
This patch makes sure that all open streams are closed when ExitToShell
is called (e.g., if the program crashes and you type "es" in MacsBug, or
if you use Command-Option-Escape to force quit the program). This keeps
MacTCP happy. It doesn't always work, but it helps sometimes.
Open Transport has its own mechanisms for doing this, so this patch
is only installed if we are using MacTCP.
----------------------------------------------------------------------------*/
static void MyExitToShell (void)
{
SetCurrentA5();
SetToolTrapAddress(gOldExitToShellUPP, _ExitToShell);
ReleaseStreams();
ExitToShell();
}
/*----------------------------------------------------------------------------
PatchExitToShell
Install a patch on the ExitToShell trap (for MacTCP only).
----------------------------------------------------------------------------*/
static void PatchExitToShell (void)
{
gOldExitToShellUPP = GetToolTrapAddress(_ExitToShell);
gMyExitToShellUPP =
NewRoutineDescriptor((ProcPtr)MyExitToShell, kPascalStackBased, GetCurrentISA());
SetToolTrapAddress(gMyExitToShellUPP, _ExitToShell);
}
static void
InitOutChunks(void)
{
short nnn, sz, bsize;
for (nnn=0;nnn<kNumOutChunks;nnn++) {
if (nnn<kNumSmallOut)
bsize = kSmallOutSize;
else if (nnn<kNumMidOut)
bsize = kMidOutSize;
else
bsize = kLargeOutSize;
sz = bsize + sizeof(OutChunk);
sz -= 2; // important bytes
outChunk[nnn] = (OutChunk *) NewPtr(sz);
verify(outChunk[nnn]);
memset(outChunk[nnn], 0, sz);
outChunk[nnn]->bufSize = bsize;
}
}
OSErr NetInit (void)
{
short i;
OSErr err = noErr;
long mtu;
gMacTCPDNRResultProcUPP = NewResultProc(MacTCPDNRResultProc);
gMacTCPCloseStreamCompletionRoutineUPP =
NewTCPIOCompletionProc(MacTCPCloseStreamCompletionRoutine);
err = OpenDriver("\p.IPP", &gRefNum);
if (err != noErr) return err;
mtu = GetMaxTCPMTU();
gTCPBufSize = 8 * mtu;
if (gTCPBufSize < kMinTCPBufSize) gTCPBufSize = kMinTCPBufSize;
gStreamBufSize = sizeof(TStream) - 1 + gTCPBufSize;
// PatchExitToShell();
for (i = 0; i < kMaxStreams; i++) {
myStream[i] = NewStreamBuffer();
if (!myStream[i]) return -1;
myStream[i]->myID = i;
bufdata[i] = 0;
}
if (err = NetGetMyAddr(&gMyAddress)) {
VDebugStr("Error getting my address.");
return err;
}
InitOutChunks();
return noErr;
}
static OSErr
GetConnectionStatus(TStreamPtr s)
{
OSErr err = noErr;
InitMacTCPParamBlock(&s->pBlock, TCPStatus);
s->pBlock.tcpStream = s->tcpStream;
err = CallMacTCP(s, true);
return err;
}
#if TIMESTAMP
long process_chars_from_server(char *buf, long len);
#include "timeseal.h"
#endif
static void
Upkeep(void)
{
short nnn;
TStreamPtr s;
unsigned long dat;
unsigned short rd;
short conn;
static short lastcon = -1;
unsigned char *dest;
for (nnn=0;nnn<kMaxStreams;nnn++) {
s = myStream[nnn];
if (s->tcpStream)
if (!GetConnectionStatus(s)) {
// do reading in stuff
dat = s->pBlock.csParam.status.amtUnreadData;
conn = s->pBlock.csParam.status.connectionState;
/* if (conn != lastcon) {
lastcon = conn;
tprintf("\r#####%d####\r", conn);
}*/
rd = dat;
if (rd > 0) {
// don't read too many bytes
if (bufdata[nnn] + rd > kBufferLength)
rd = kBufferLength - bufdata[nnn];
dest = &buf[nnn][bufdata[nnn]];
if (DoTCPRcv(s, (Ptr) dest, &rd))
VDebugStr("Error reading data.");
#if TIMESTAMP
if (gPrefs.serverType == kIcc && gPrefs.timeseal) {
bufdata[nnn] += process_chars_from_server((char *) dest, rd);
}
else if (gPrefs.serverType == kFics && gPrefs.timeseal) {
bufdata[nnn] += SealFromServer((char *) dest, rd);
}
else
#endif
bufdata[nnn] += rd;
// tprintf("Data: %u\r", rd);
break;
}
// give rest of world some status on this connection
// nice of Apple to provide these constants in the header
switch (conn) {
// next line handled better in Release
// case 0: case 14: nexStatus[nnn] = kStatClosed; break;
case 2: case 4: nexStatus[nnn] = kStatListening; break;
case 8: nexStatus[nnn] = kStatOpen; break;
default: nexStatus[nnn] = kStatOther; break;
}
// check for closed connection
// it seems to hang on 14, so why not close it (???)
if (conn == 0 || conn == 14) {
if (!DoTCPRelease(nnn))
tprintf("Connection terminated\r");
}
}
else {
// VDebugStr("Error getting connection status stream %d", nnn);
// somehow this connection closed without us knowing
nexStatus[nnn] = kStatClosed;
DoTCPRelease(nnn); // ???
}
}
}
OSErr NetIdle (void)
{
TStreamPtr s, nextClose, prev = nil;
OSErr err = noErr;
short nnn;
for (nnn=0;nnn<kMaxStreams;nnn++) {
s = myStream[nnn];
if (s->release) {
err = DoTCPRelease(nnn);
// DisposeStreamBuffer(s);
}
}
Upkeep();
return noErr;
}
/*----------------------------------------------------------------------------
NetNameToAddr
Translate a domain name to an IP address.
Entry: name = C-format domain name string, optionally followed by a
comma, space, or colon and then the port number.
defaultPort = default port number.
Exit: function result = error code.
*addr = IP address.
*port = port number.
----------------------------------------------------------------------------*/
OSErr NetNameToAddr (char *name,
unsigned long *addr, unsigned short *port)
{
OSErr err = noErr, giveTimeErr = noErr;
short i;
struct hostInfo hInfoMacTCP;
Boolean done = false;
char domainName[256];
char *p, *q;
p = name;
q = domainName;
while (*p != 0) *q++ = *p++;
*q = 0;
/* while (*p != 0 && *p != ',' && *p != ' ' && *p != ':') *q++ = *p++;
*q = 0;
q = p;
while (*q == ' ') q++;
if (*q == 0) {
*port = defaultPort;
} else {
p++;
if (!isdigit(*p)) return -1;
q = p+1;
while (isdigit(*q)) q++;
while (*q == ' ') q++;
if (*q != 0) return -1;
*port = atoi(p);
}
*/
while (gMacTCPDNROperationInProgress) {
/* Some other thread is using the DNR. Wait for it to finish. */
// err = (*gGiveTime)();
// if (err != noErr) return err;
}
err = OpenResolver(nil);
if (err != noErr) return err;
memset(&hInfoMacTCP, 0, sizeof(hInfoMacTCP));
gMacTCPDNROperationInProgress = true;
err = StrToAddr(domainName, &hInfoMacTCP, gMacTCPDNRResultProcUPP, (char*)&done);
if (err == cacheFault) {
err = noErr;
while (!done) {
// giveTimeErr = (*gGiveTime)();
// if (err == noErr) err = giveTimeErr;
}
if (err == noErr) err = hInfoMacTCP.rtnCode;
}
gMacTCPDNROperationInProgress = false;
// (*gGiveTime)();
CloseResolver();
if (err != noErr) return err;
*addr = hInfoMacTCP.addr[0];
return noErr;
}
/*----------------------------------------------------------------------------
NetAddrToName
Translate an IP address to a domain name.
Entry: addr = IP address.
Exit: function result = error code.
name = domain name, as a C-format string.
----------------------------------------------------------------------------*/
OSErr NetAddrToName (unsigned long addr, char *name)
{
struct hostInfo hInfoMacTCP;
OSErr err = noErr, giveTimeErr = noErr;
Boolean done=false;
while (gMacTCPDNROperationInProgress) {
/* Some other thread is using the DNR. Wait for it to finish. */
// err = (*gGiveTime)();
// if (err != noErr) return err;
}
err = OpenResolver(nil);
if (err != noErr) return err;
memset(&hInfoMacTCP, 0, sizeof(hInfoMacTCP));
gMacTCPDNROperationInProgress = true;
err = AddrToName(addr, &hInfoMacTCP, gMacTCPDNRResultProcUPP, (char*)&done);
if (err == cacheFault) {
err = noErr;
while (!done) {
// giveTimeErr = (*gGiveTime)();
// if (err == noErr) err = giveTimeErr;
}
if (err == noErr) err = hInfoMacTCP.rtnCode;
}
gMacTCPDNROperationInProgress = false;
// (*gGiveTime)();
CloseResolver();
if (err != noErr) return err;
hInfoMacTCP.cname[254] = 0;
strcpy(name, hInfoMacTCP.cname);
return noErr;
}